package cc.htdf.gwc.datacompare.service.impl;

import cc.htdf.gwc.datacompare.algorithm.QcMethod;
import cc.htdf.gwc.datacompare.algorithm.impl.BaseQcMethod;
import cc.htdf.gwc.datacompare.domain.DataCompare;
import cc.htdf.gwc.datacompare.domain.response.ResponseBody;
import cc.htdf.gwc.datacompare.domain.response.ResponseCode;
import cc.htdf.gwc.datacompare.repository.DataCompareRepository;
import cc.htdf.gwc.datacompare.service.DataCompareService;
import cc.htdf.gwc.datacompare.service.ForecaseDataService;
import cc.htdf.gwc.datacompare.service.ObserveDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import whisper.common.exception.check.EmptyDataException;
import whisper.common.exception.sql.UniqueKeyException;
import whisper.common.utils.DateUtils;

import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by JT on 2017/10/11.
 */
@Service
public class DataCompareServiceImpl implements DataCompareService {

    @Autowired
    private ForecaseDataService forecaseDataService;

    @Autowired
    private ObserveDataService observeDataService;

    @Autowired
    private DataCompareRepository dataCompareRepository;

    private static final String[] stations = new String[]{"CD56181","CD56187","CD56188","CD56189","CD56272","CD56276","CD56281","CD56284","CD56285","CD56286","CD56288","CD56290","CD56295","CD56296"};



    @Override
    public void dataCompare(String lastDateCompare) {

        /**
         * 实况数据获取
         */
        String observeStations = String.join(",", stations).replace("CD", "");
        String observeElements = "PRECIPITATION, TEMPERATURE";
        ResponseBody observeBody = observeDataService.fetchChengDuObserveDataByStationsAndDate(observeStations, lastDateCompare, observeElements);
        List<Map<String, Object>> observeDatas = (List<Map<String, Object>>) observeBody.getData();

        if (!observeDatas.isEmpty()) {
            /**
             * 预报数据获取
             */
            String forecastStations = String.join(",", stations);
            String forecastElements = "QOP1HR,TEMPERATURE";
            ResponseBody forecastBody = forecaseDataService.fetchForcastDataByValidDate(forecastStations, forecastElements, lastDateCompare);
            List<Map<String, Object>> forecastDatas = (List<Map<String, Object>>) forecastBody.getData();

            /**
             * 实况预报对比
             */
            if (!forecastDatas.isEmpty()) {
                List<DataCompare> dataList = new ArrayList<>();
                List<DataCompare> tempList = new ArrayList<>();
                Iterator observeDataIterator = observeDatas.iterator();
                while (observeDataIterator.hasNext()) {
                    Map<String, Object> observeData = (Map<String, Object>) observeDataIterator.next();
                    String observeStation = "CD" + observeData.get("SITE_ID");
                    String observePrecipitation = (String) observeData.get("PRECIPITATION");
                    String observeTemperature = (String) observeData.get("TEMPERATURE");

                    QcMethod qcMethod = new BaseQcMethod();
                    tempList = forecastDatas.stream().filter(data -> {
                        return observeStation.equals(String.valueOf(data.get("STATIONID")));
                    }).map(data -> {
                        DataCompare dataCompare = new DataCompare();
                        dataCompare.setStation(observeStation);
                        dataCompare.setModelRunDateTime((String) data.get("MODELRUNDATETIME"));
                        dataCompare.setValidDateTime(lastDateCompare);
                        // 降水量预报值、实况值、差值
                        String forecastPrecipitation = String.valueOf(data.get("QOP1HR"));
                        dataCompare.setForecastQop1hrValue(forecastPrecipitation);
                        dataCompare.setObservationQop1hrValue(observePrecipitation);
                        if (qcMethod.checkMissing(forecastPrecipitation) && qcMethod.checkMissing(observePrecipitation)) {
                            dataCompare.setDifferenceQop1hrValue(String.format("%.4f", Math.abs(Double.valueOf(forecastPrecipitation) - Double.valueOf(observePrecipitation))));
                        } else {
                            dataCompare.setDifferenceQop1hrValue("0");
                        }
                        // 温度预报值、实况值、差值
                        String forecastTemperature = String.valueOf(data.get("TEMPERATURE"));
                        dataCompare.setForecastTemperatureValue(forecastTemperature);
                        dataCompare.setObservationTemperatureValue(observeTemperature);
                        if (qcMethod.checkMissing(forecastTemperature) && qcMethod.checkMissing(observeTemperature)) {
                            dataCompare.setDifferenceTemperatureValue(String.format("%.4f", Math.abs(Double.valueOf(forecastTemperature) - Double.valueOf(observeTemperature))));
                        } else {
                            dataCompare.setDifferenceTemperatureValue("0");
                        }
                        return dataCompare;
                    }).collect(Collectors.toList());
                    dataList.addAll(tempList);
                    tempList.clear();
                }

                try {
                    dataCompareRepository.batchSaveCompareData(dataList);
                } catch (Exception e) {
                    throw new UniqueKeyException(ResponseCode.STATUS_ERROR, "时间冲突[" + lastDateCompare + "]，存在该时次的对比数据！");
                }
            }
        } else {
            throw new EmptyDataException(ResponseCode.STATUS_ERROR, "实况数据为空！");
        }

    }

    /**
     * 根据发布时间、预报次数、要素 查询值的平均差
     *
     * @param modelRunDateTime ：发布时效  "yyyyMMddHH"
     * @param validTimes       ：预报次数 例如： "96","360"
     */
    @Override
    public Map<Object, Map<String, Object>> findCompareDatasByModelRunDateTimeAndTimes(String modelRunDateTime, String validTimes) throws whisper.common.exception.format.ParseException {
        String startValidTime = "", endValidTime = "";
        try {
            startValidTime = DateUtils.format(modelRunDateTime, "yyyyMMddHH", "yyyy-MM-dd HH:mm:ss");
            endValidTime = DateUtils.addHour(startValidTime, Integer.valueOf(validTimes), "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss");
        } catch (ParseException e) {
            throw new whisper.common.exception.format.ParseException(ResponseCode.STATUS_ERROR, "时间格式转换错误，请检查转入时间格式 ！");
        }
        List<Map<String, Object>> dataList = dataCompareRepository.findCompareDatasByModelRunDateTimeAndTimes(modelRunDateTime, startValidTime, endValidTime);

        /* 统计数据 */
        Map<String, List<Double>[]> totalMap = new LinkedHashMap<>();
        Iterator dataIterator = dataList.iterator();
        while (dataIterator.hasNext()) {
            Map<String, Object> map = (Map<String, Object>) dataIterator.next();
            String key = String.valueOf(map.get("VALIDDATETIME"));
            List<Double>[] values;
            if (totalMap.containsKey(key)) {
                values = totalMap.get(key);
            } else {
                values = new List[2];
                values[0] = new ArrayList<>();
                values[1] = new ArrayList<>();
            }
            // 降水
            values[0].add(Double.valueOf(String.valueOf(map.get("DIFFERENCE_QOP1HR_VALUE"))));
            // 温度
            values[1].add(Double.valueOf(String.valueOf(map.get("DIFFERENCE_TEMPERATURE_VALUE"))));
            totalMap.put(key, values);
        }

        Map<Object, Map<String, Object>> meanDifferenceMap = new LinkedHashMap<>();
        Map tempMap;
        for (Map.Entry entry : totalMap.entrySet()) {
            tempMap = new HashMap();
            List[] values = (List[]) entry.getValue();
            Double sumQop1hr = 0.0, sumTemp = 0.0;
            for (Integer i = 0, tempsize = values[0].size(); i < tempsize; i++ ) {
                sumQop1hr = sumQop1hr + Double.valueOf(String.valueOf(values[0].get(i)));
                sumTemp = sumTemp + Double.valueOf(String.valueOf(values[1].get(i)));
            }
            tempMap.put("QOP1HR_MEANDIFFERENCE", String.format("%2f", sumQop1hr/values[0].size()));
            tempMap.put("TEMPERATURE_MEANDIFFERENCE", String.format("%2f", sumTemp/values[1].size()));
            meanDifferenceMap.put(entry.getKey(), tempMap);
        }
        return meanDifferenceMap;
    }
}
